package com.sprucetec.live.mcq.process;

import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.sprucetec.live.common.dto.business.LiveChatDto;
import com.sprucetec.live.common.dto.business.LiveVideoDto;
import com.sprucetec.live.enums.LiveHighConcurrncyCategoryEnum;
import com.sprucetec.live.mcq.McqBusinessMemoryMap;
import com.sprucetec.live.mcq.category.ConsumerProcess;
import com.sprucetec.live.mcq.category.ScheduledProcess;
import com.sprucetec.live.service.LiveChatService;
import com.sprucetec.live.service.RedisService;
import com.sprucetec.live.utils.SpringContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.sql.Time;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @ClassName LiveChatMsgProcess
 * @Description:
 * @Author Kenny
 * @Date 2020/4/4
 **/
@Slf4j
@Component("liveChatMsgProcess")
public class LiveChatMsgProcess {


    @Autowired
    private RedisService redisService;

    @Autowired
    private ConsumerProcess consumerProcess; // 阻塞队列处理策略

    @Autowired
    private LiveChatService liveChatService;

    private Lock lock = new ReentrantLock();

    @Value("${system.high.concurrency.category}")
    private String isHighConcurrncyCategory; // 超高并发策略

    @Value("${system.high.concurrency}")
    private boolean isHighConcurrncy; // 是否开启超高并发模式

    @Autowired
    private ThreadPoolTaskExecutor liveChatThreadPool;

    @Autowired
    private ThreadPoolTaskExecutor chatCustomerThreadPool;// 聊天消费线程池

    public void processChatMessage(String jsonObject) {
        log.info("收到消息=>" + jsonObject);
        if (StringUtils.isBlank(jsonObject)) {
            return;
        }
        try {
            LiveChatDto liveChatDto = JSONObject.parseObject(jsonObject, LiveChatDto.class);
            if (isHighConcurrncy) {
                if (isHighConcurrncyCategory.equals(LiveHighConcurrncyCategoryEnum.SCHEDULED.getType())) {
                    chatCustomerThreadPool.execute(() -> { // 线程池异步消费防止内部锁机制导致mcq消息挤压
                        scheduleProcess(liveChatDto); // 定时任务方式批量入库
                    });
                } else if (isHighConcurrncyCategory.equals(LiveHighConcurrncyCategoryEnum.BLOCK_QUEUE.getType())) {
                    chatCustomerThreadPool.execute(() -> { // 线程池异步消费防止内部锁机制导致mcq消息挤压
                        consumerProcess.processChatMessage(liveChatDto); // 阻塞队列方式入库
                    });
                } else { // 默认直接入库
                    liveChatService.insertChatByMq(liveChatDto);
                }
            } else {
                liveChatService.insertChatByMq(liveChatDto);
            }
            redisService.chatDataOnVideo(liveChatDto);
        } catch (Exception ex) {
            log.error("MCQ消费端消息消费报错:{}", ex.toString());
        }
    }

    /**
     * 定时任务批量插入方式
     *
     * @param liveChatDto
     */
    public void scheduleProcess(LiveChatDto liveChatDto) {
        ScheduledProcess scheduledProcess = null;
        try {
            lock.lock();
            scheduledProcess = McqBusinessMemoryMap.scheduledProcessHashMap.get(liveChatDto.getVideoId());
            if (scheduledProcess == null) {
                scheduledProcess = (ScheduledProcess) SpringContextUtil.getBean("scheduledProcess");
                McqBusinessMemoryMap.scheduledProcessHashMap.put(liveChatDto.getVideoId(), scheduledProcess);
            }

        } finally {
            lock.unlock();
        }
        if (scheduledProcess != null) {
            scheduledProcess.processChatMessage(liveChatDto);
        }
    }


    public void processVideoDataMessage(String jsonObject) {
        if (StringUtils.isBlank(jsonObject)) {
            return;
        }
        LiveVideoDto liveVideoDto = JSONObject.parseObject(jsonObject, LiveVideoDto.class);
        redisService.videoDetailData(liveVideoDto);
    }

}
